package org.elip.stewiemaze.client;

import org.elip.stewiemaze.shared.entities.Player;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

public class Stewiemaze implements EntryPoint {

	private DatastoreServiceAsync _datastoreService;
	private FacebookServiceAsync _facebookService;

	@Override
	public void onModuleLoad() {

		/* Get a reference to the datastore imple class for calls to the datastore */
		_datastoreService = (DatastoreServiceAsync)GWT.create(DatastoreService.class);
		((ServiceDefTarget)_datastoreService).setServiceEntryPoint("/stewiemaze/datastoreService");

		/* Get a reference to the facebook imple class for calls to the facebook details */
		_facebookService = (FacebookServiceAsync)GWT.create(FacebookService.class);
		((ServiceDefTarget)_facebookService).setServiceEntryPoint("/stewiemaze/facebookService");

		/* Add a button to retrieve the highscore from the database
		 * this button is clicked by javascript when a game ends */
		addRetrieveRecordsButton();

		/* Check for cookies in the page */
		String nickname = Cookies.getCookie("nickname");
		String highscore = Cookies.getCookie("highscore");
		String token = Cookies.getCookie("accesToken");

		/* if cookies exist, display the nickname and highscore */
		if ((nickname != null) && (highscore != null) && token == null) {
			addHelloFriendPanel(nickname, highscore);
			addExitButton();
			RootPanel.get("register-form").clear();
			RootPanel.get("social-plugins").clear();
		}
		else {

			/* If no cookies are found, but the user is connected to facebook and to my app then set cookies
			 * by calling the server for the username and highscore saved in the database  
			 */
			String accesToken = Cookies.getCookie("accesToken");
			if (accesToken != null) {
				_facebookService.getUsername(accesToken, new AsyncCallback<String>() {

					@Override
					public void onSuccess(final String result) {
						if (result == null) {
							Window.alert("lookes like you deletes the app from your facebook account...");
							Cookies.removeCookie("accesToken");
							Cookies.removeCookie("nickname");
							Cookies.removeCookie("highscore");
							Cookies.removeCookie("tempScore");
							addLoginPanel();
							closeModalWindow();
						}
						else {
							_datastoreService.retrieveFacebookPlayer(result, new AsyncCallback<Player>() {	
								@Override
								public void onSuccess(Player player) {
									if (player != null) {
										Cookies.setCookie("nickname", player.getNickname());
										Cookies.setCookie("highscore", player.getHighscore() + "");
										addHelloFriendPanel(result, player.getHighscore() + "");
										addWarning();
										addSocialPlugins();
										closeModalWindow();
									}
								}

								@Override
								public void onFailure(Throwable caught) {

								}
							});
						}
					}

					@Override
					public void onFailure(Throwable caught) {

					}
				});
				showModal();
				//Window.alert("retrieving information from facebook, this may take a couple of seconds...");
			}
			/* if there are no cookies, and the access token is null, give the user a chance to login */
			else {
				addLoginPanel();	
			}	
		}
	}

	private native void closeModalWindow() /*-{
		$wnd.TINY.box.hide();

	}-*/;

	private native void addSocialPlugins() /*-{
		$doc.getElementById('social-plugins').style.visibility='visible';

	}-*/;
	
	private native void showModal() /*-{
		$wnd.TINY.box.show({image:'css/images/slideShowLoader.gif',boxid:'frameless',animate:true, close:false})


	}-*/;

	private void addLoginPanel() {
		RootPanel rootPanel = RootPanel.get("login_area");
		Label nicknameLabel = new Label("Nickname:");
		nicknameLabel.addStyleName("instructions-style");
		final TextBox nicknameTextBox = new TextBox();
		Label passwordLabel = new Label("Password:");
		passwordLabel.addStyleName("instructions-style");
		final PasswordTextBox password = new PasswordTextBox();

		ClickHandler loginHander = new ClickHandler() {

			@Override
			public void onClick(ClickEvent event) {
				String nickname = nicknameTextBox.getText();
				String passwordS = password.getText();

				AsyncCallback<Player> callback = new AsyncCallback<Player>() {

					@Override
					public void onSuccess(Player result) {
						if (result != null) {
							Cookies.setCookie("nickname", result.getNickname());
							Cookies.setCookie("highscore", result.getHighscore() + "");
							Window.Location.reload();
						}
						else {
							showErrorModal();
							//Window.alert("Wrong user name or password");
						}
					}

					@Override
					public void onFailure(Throwable caught) {

					}
				};
				_datastoreService.retrievePlayer(nickname, passwordS, callback);
			}
		};
		Button login = new Button("login", loginHander);
		login.addStyleName("button");
		Label registered = new Label("If youre registered, why not login?");
		registered.addStyleName("instructions-style");
		HorizontalPanel hPanel = new HorizontalPanel();
		hPanel.setSpacing(2);
		hPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
		hPanel.add(nicknameLabel);
		hPanel.add(nicknameTextBox);
		hPanel.add(passwordLabel);
		hPanel.add(password);
		hPanel.add(login);
		hPanel.add(registered);
		rootPanel.add(hPanel);
		rootPanel.getElement().setAttribute("style", "visibility: visible");

	}

	private native void showErrorModal() /*-{
		$wnd.TINY.box.show({html:'Wrong username or password!',animate:false,close:false,boxid:'error',top:5})
	}-*/;

	private void addHelloFriendPanel(String nickname, String highscore) {
		Cookies.removeCookie("tempScore");
		Label hello = new Label("hello " + nickname + " , your highscore is : " + highscore);
		hello.getElement().setId("hello-panel");
		hello.addStyleName("instructions-style");
		RootPanel.get("hello-friend").getElement().appendChild(hello.getElement());
	}

	private void addWarning() {
		HTML warn = new HTML("NOTE : logging out of facebook without refreshing the page will cause unexpected behavior");
		warn.addStyleName("instructions-style");
		RootPanel.get("hello-friend").getElement().appendChild(warn.getElement());
	}

	private void addRetrieveRecordsButton() {
		ClickHandler recordsHandler = new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				showScoresModal();
				final String tempScore = Cookies.getCookie("tempScore");
				final String nickname = Cookies.getCookie("nickname");
				if (Integer.parseInt(tempScore) > Integer.parseInt(Cookies.getCookie("highscore")) ) {
					_datastoreService.updateScore(nickname, tempScore, new AsyncCallback<String[]>() {

						@Override
						public void onSuccess(String[] result) {
							Cookies.setCookie("highscore", tempScore);
							updateHighscoreLabel(nickname, tempScore);
							addRecords(result);
							closeScoresModal();
						}

						@Override
						public void onFailure(Throwable caught) {

						}
					});

				}
				else {
					_datastoreService.retrieveRecordsTable(new AsyncCallback<String[]>() {
						@Override
						public void onSuccess(String[] result) {
							if (result != null) {
								addRecords(result);
								closeScoresModal();
							}
							else {
								Window.alert("No scores found");
								closeScoresModal();
							}	
						}
						@Override
						public void onFailure(Throwable caught) {


						}
					});

				}
			}
		};
		Button retrieveRecordTable = new Button("", recordsHandler);
		retrieveRecordTable.setVisible(false);
		RootPanel.get("record_table_get_area").add(retrieveRecordTable);

	}	

	private void addRecords(String[] records) {
		RootPanel.get("records_table_area").clear();
		ScrollPanel recordsPanel = new ScrollPanel();
		VerticalPanel vPanel = createRecordsPanel(records);
		HorizontalPanel hPanel = new HorizontalPanel();
		hPanel.setSpacing(5);
		vPanel.add(hPanel);
		recordsPanel.add(vPanel);
		RootPanel.get("records_table_area").add(recordsPanel);
	}

	private VerticalPanel createRecordsPanel(String[] records) {

		VerticalPanel vPanel = new VerticalPanel();
		for (String s : records) {
			HTML score = new HTML(s);
			score.addStyleName("instructions-style");
			vPanel.add(score);
		}
		return vPanel;
	}

	private void addExitButton() {
		/* also, add an exit button to allow other users to login */
		ClickHandler handler = new ClickHandler() {	
			@Override
			public void onClick(ClickEvent event) {

				/* The exit button deletes all cookies and reloads the page */
				Cookies.removeCookie("nickname");
				Cookies.removeCookie("highscore");
				Cookies.removeCookie("tempScore");
				Window.Location.reload();

			}
		};
		Button exit = new Button("exit");
		exit.addStyleName("button");
		exit.addClickHandler(handler);
		RootPanel.get("hello-friend").add(exit);
	}
	
	private native void updateHighscoreLabel(String nickname, String score) /*-{
		$wnd.$('#hello-panel').text("hello " + nickname + " , your highscore is : " + score);
	}-*/;

	private native void showScoresModal() /*-{
		$wnd.TINY.box.show({image:'css/images/img_loader.gif',boxid:'frameless',animate:true, close:false})
	}-*/;

	private native void closeScoresModal() /*-{
		$wnd.TINY.box.hide();
	}-*/;

}
